fix(skills): serve agent-bundle/meta to rendered skills and compile their JSX without the consumer react runtime - #527
Conversation
🦋 Changeset detectedLatest commit: 6d164f5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1b1a1e1f0f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Rendered skills evaluate during discovery, before normalization stamps | ||
| // the same identity into the model; `agent-bundle/meta` serves it to them | ||
| // here so a skill documents the version its plugin ships (#440). | ||
| const meta = projectMeta(pluginIdentity(projectRoot, config)); |
There was a problem hiding this comment.
Preserve validation for a missing plugin object
When a configuration exports {} or declares plugin: null, this unconditional identity calculation reaches pluginIdentity(), which dereferences config.plugin.name before validateSource can inspect the malformed value. ProjectService therefore converts the discovery exception into generic AB7000 instead of returning the established actionable AB4000 diagnostic; make identity derivation tolerate malformed plugin metadata so normal source validation can report it.
Useful? React with 👍 / 👎.
…heir JSX against the loader's element factory Rendered SKILL.tsx modules evaluate through jiti during discovery, outside the compiler's specifier replacement, so 'agent-bundle/meta' fell through to the published module and threw AB4760 inside AB3003 (#440). The loader now aliases the specifier to the same generated identity module the build stamps, fed from one pluginIdentity() derivation normalization also uses for model.metadata. The skill's JSX compiled against the consumer's react/jsx-runtime, which jiti resolves without the process's --conditions while React's own inner require('react') honours them; under the route-unit pool's react-server condition the client jsx runtime met the server React and threw (recentlyCreatedOwnerStacks) so inspectWorkbenchSurface failed with AB3005 (#441). The loader now aliases react/jsx-runtime and react/jsx-dev-runtime to its own plain element factory: the Markdown renderer never needed React. Fixes #440 Fixes #441
…n discovery derives the skill identity
Review: discovery dereferenced config.plugin.name before validateSource ran,
turning {} or plugin: null into a generic AB7000. declaredPluginIdentity()
returns undefined for an unusable plugin.name; the rendered skill then gets
no identity (AB3003) and validation reports AB4000 as before.
fb905cb to
6d164f5
Compare
Fixes #440. Fixes #441.
Both defects live in the same place — how
compileRenderedSkill(packages/agent-bundle/src/config/rendered-skill.ts) loads a renderedSKILL.tsxthrough jiti — so they ship together.Root causes
compileRenderedSkill(rendered-skill.ts:61-73before this PR) evaluated the module through jiti with no alias, soagent-bundle/metaresolved to the publisheddist/meta.js, whose every binding throwsAB4760; the skill loader reported it asAB3003. Discovery runs before any bundle exists, so the compiler's specifier replacement never applied to skills.react/jsx-runtime. jiti resolves package subpaths with fixed["node","require"]/["node","import"]conditions (it ignores the process's--conditions), so it loaded the clientreact/jsx-runtime.js; but React's own internalrequire("react")inside that runtime honours--conditions=react-serverand returned the server build, whose shared internals lackrecentlyCreatedOwnerStacks→ the throw insidejsx()thatinspectWorkbenchSurfacesurfaced asAB3005. (The issue's guess aboutjsx-dev-runtimewas close but not exact: jiti's babel plugin usesdevelopment: false; the failing frame isreact-jsx-runtime.development.js:326becauseNODE_ENVis unset.)Fix
src/config/plugin-identity.ts:pluginIdentity(projectRoot, config)—plugin.name, thepackage.jsonaxes, and the resolved plugin version — extracted fromnormalizeProject(which now calls it formodel.metadata), so discovery and normalization derive one identity.compileRenderedSkill(source, { meta })writes two generated modules into a privatemkdtempdirectory (nothing is written under the project;validatestays read-only) and passes them to jiti asalias:agent-bundle/meta→generatedMetaModuleSource(meta), the exact module the build injects;react/jsx-runtimeandreact/jsx-dev-runtime→ a plain element factory ({ $$typeof, type, key, props }+Fragment = Symbol.for('react.fragment')), which is allrenderElementToMarkdownever walked. The skill's ownimport React from 'react'still resolves from the project as before.discoverProjectpassesprojectMeta(pluginIdentity(root, config)); the WorkbenchSkillDocumentServicepassesprojectMeta(model.metadata)when it re-parses source skills.parseSkillgains an optional 4thoptionsargument.docs/entry-conventions.md(meta reference),docs/diagnostics.md(AB4760 section), and the Skills authoring guide (en + zh).Tests
rendered-skills.test.ts: a skill importing{ meta, name, packageName, packageVersion, version }renders the identitynormalizeProjectstamps (package.json axes, authoredplugin.versionprecedence), and a directparseSkillwithout an identity still reportsAB3003; a fixture whosenode_modules/react/jsx-runtime.jsthrows proves the loader never resolves the consumer runtime whilekeyed lists andimport React from 'react'still work.tests/route-unit/workbench-surface-rendered-skill.test.ts: runs in the repo'sagentBundleRstest()route-unit pool (--conditions react-server, asserted) and callsinspectWorkbenchSurfaceon a project with a rendered skill that importsagent-bundle/metaandreact— the exact inspectWorkbenchSurface fails on projects with a rendered SKILL.tsx under the react-server condition (AB3005 recentlyCreatedOwnerStacks) #441 shape. Fails onmain(AB3003: Cannot find module 'agent-bundle/meta'; with the import removed, therecentlyCreatedOwnerStacksAB3005), passes here.agent-bundle validaterendersHello **world** from version \0.0.1`,agent-bundle buildemits it intoskills/demo/SKILL.md, andnode probe.mjs/node --conditions=react-server probe.mjsboth printOK skills: 1`.pnpm test:unit3247 passed,pnpm test:route-unit59 passed,pnpm typecheck,pnpm lint,pnpm docs:site:buildclean.Consumer follow-up
cargo-hauler's rendered skill can import
versionfromagent-bundle/metaagain (the "prints no version for now" workaround in #440), and itstests/workbench-surface.test.tscan move into the route-unit pool beside the other harness levels (the plain-pool workaround in #441).Review status
1b1a1e1opened one P2 thread (discover.ts:261:pluginIdentity()dereferencedconfig.plugin.namebeforevalidateSource, so{}/plugin: nullbecame a genericAB7000). Addressed infb905cb8e: discovery now usesdeclaredPluginIdentity(), which returnsundefinedfor an unusableplugin.name; the skill is then served no identity (its ownAB3003) and validation reportsAB4000as before — covered by a new assertion over{},{ plugin: null },{ plugin: { name: '' } }, and{ plugin: 'x' }. No reply was posted on the thread by request; this note is the response.Release gatesrun failed inpackages/workbench/tests/packed-release.e2e.test.ts("foreground outage ledger quiet fence … net::ERR_ABORTED" during browser navigation), unrelated to this change (no skill/meta diagnostic involved; the same job passed on fix(routes): follow re-exported default components in the route contract check (AB4810) #524); re-run.1b1a1e1f0. Unreviewed heads:0bf21b704,fb905cb8e(the review fix), then the rebase ontomainafter fix(routes): follow re-exported default components in the route contract check (AB4810) #524 (9a3abdd63,af5710e1e,6d164f5a3). No@codex reviewwas requested by instruction (no PR comments); merged on green CI per the reviewer-fallback rule.